module Zeno.Function where

import Prelude ()
import StdImports
import qualified Data.Set as Set
import Zeno.Term

data Function a 
  = Function  { funcName :: a,
                funcParameters :: ![a],
                funcExpression :: !(Expression a) }
  deriving ( Eq, Functor, Foldable, Traversable )

data Expression a 
  = CaseOf !Id !(Term a) ![When a]
  | Value !(Term a)
  deriving ( Eq, Functor, Foldable, Traversable )

data When a
  = When !(Term a) !(Expression a)
  deriving ( Eq, Functor, Foldable, Traversable )

instance WithinTraversable (Term a) (Expression a) where
  mapWithinM f (CaseOf id t ws) = do
    ws' <- mapM (mapWithinM f) ws
    t' <- mapWithinM f t
    return (CaseOf id t' ws')
  mapWithinM f (Value t) =
    Value `liftM` (mapWithinM f t)

instance WithinTraversable (Term a) (When a) where
  mapWithinM f (When t expr) =
    When `liftM` (mapWithinM f t) `ap` (mapWithinM f expr)
    
instance Show a => Show (Function a) where
  show (Function name params expr) =
    let params' = intercalate " " (map show params)
        expr' = runReader (showExpr expr) 1
        name' = show name
    in name' ++ " " ++ params' ++ " = " ++ expr'
   
showWhen :: Show a => When a -> Indented String
showWhen (When term expr) = do
  i <- indentation
  expr' <- indent $ showExpr expr
  return $ i ++ (show term) ++ " -> " ++ expr' 

instance Show a => Show (Expression a) where
  show = (flip runReader 0) . showExpr 
  
showExpr :: Show a => Expression a -> Indented String
showExpr (Value t) = do
  i <- indentation
  return $ i ++ show t
showExpr (CaseOf id t ws) = do
  i <- indentation
  ws' <- indent $ mapM showWhen ws
  return $ i ++ "case{" ++ (show id) ++ "} " ++ (show t) ++ " of" ++ (concat ws')


